package cn.itcast.zt.luaLock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author zhangtian105
 * @ClassName RedisUtil.java
 * @projectName Redis
 * @Description Redis lua工具类
 * @createTime 2020年11月19日 10:21:00
 */
@Component
public class RedisUtil {
    @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    /**
     * 计数器限流法 https://blog.csdn.net/qq_42005625/article/details/106425252
     * @param scriptFile   文件地址
     * @param keys  限流的key
     * @param count 限流的数
     * @param second 单位时间（秒）
     * @return
     */
    public Integer rateLimitLua(String scriptFile, List<String> keys, String count, String second) {
        Resource resource = new ClassPathResource(scriptFile);
        ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
        DefaultRedisScript script = new DefaultRedisScript();
        script.setScriptSource(scriptSource);
        script.setResultType(Long.class);

        Integer cnt = Integer.parseInt(stringRedisTemplate.execute(script, keys,count,second).toString());
        return cnt;
    }

    /**
     * 令牌桶限流法 https://blog.csdn.net/qq_42005625/article/details/106425252
     * @param scriptFile 文件地址
     * @param keys 限流的key
     * @param maxNum 桶最大容量
     * @param count 每次添加的令牌数
     * @param second 令牌添加时间间隔（秒）
     * @param timestamp 当前时间戳
     * @return
     */
    public Integer rateBucketLimit(String scriptFile,List<String> keys,String maxNum, String count, String second, String timestamp){
        Resource resource = new ClassPathResource(scriptFile);
        ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
        DefaultRedisScript script = new DefaultRedisScript();
        script.setScriptSource(scriptSource);
        script.setResultType(Long.class);

        Integer tokenCnt = Integer.parseInt(stringRedisTemplate.execute(script, keys, maxNum, count, second, timestamp).toString());
        return tokenCnt;
    }

    /**
     * 功能描述: <br>
     * 〈续租时间〉
     * @Param: [keys 锁的key, oldExpireV 旧值, newExpireV 续期新值]
     * @Return: java.lang.Integer 
     * @Author: zhangtian105
     * @Date: 2020/11/19 10:33
     */
    public Long leaseTime(List<String> keys, String requestID, String newExpireV) {
        DefaultRedisScript<Long> script = new DefaultRedisScript();
        script.setResultType(Long.class);
        script.setScriptText(RedisLuaScript.LOCK_LEASE_SCRIPT); // 可以使用文本直接传，也可以加载文件

        Long addTimeStatus = stringRedisTemplate.execute(script, keys, requestID, newExpireV) ;
        return addTimeStatus ;
    }

    /**
     * 功能描述: <br>
     * 〈解锁〉
     * @Param: [keys 锁的key, requestID 锁中存的数据（避免其他锁设置的requestID不同，将我的锁清除掉了）]
     * @Return: java.lang.Integer 
     * @Author: zhangtian105
     * @Date: 2020/11/19 10:47
     */
    public Long unlock(List<String> keys, String requestID) {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(RedisLuaScript.UN_LOCK_SCRIPT); // 可以使用文本直接传，也可以加载文件

        Long addTimeStatus = stringRedisTemplate.execute(script, keys, requestID) ;
        return addTimeStatus ;
    }
}
